#include "Common.fxh"

SamplerState Trilinear
{
	Filter = MIN_MAG_MIP_LINEAR;
	AddressU = Clamp;
	AddressV = Clamp;
};

Texture3D gLightTex0;
Texture3D gLightTex1;
Texture3D gLightTex2;
#ifndef AXES_4
Texture3D gLightTex3;
Texture3D gLightTex4;
#endif
//Texture3D gLightTex4;
//Texture3D gLightTex5;

cbuffer cbPerFrame
{
	float4x4 gViewProjMatrix;
	float3 gEyePosW;
	float3 gAxis0;
	float3 gAxis1;
	float3 gAxis2;
	float3 gAxis3;
};

cbuffer cbPerObject
{
	//float4x4 gWorldMatrix;
	float3 gLightVolPos;
	float3 gLightVolScale;
	float gLightTexOffsetX;
};

Texture2D gDiffuseMap;

struct VS_IN
{
	float3 posL : POSITION;
	float2 texCoord : TEXCOORD0;
	float size : TEXCOORD1;
	float opacity : TEXCOORD2;
};

struct VS_OUT
{
	float4 posH : SV_POSITION;
	float3 posW : TEXCOORD0;
	float2 texCoord : TEXCOORD1;
	float3 lightVolumeTexCoord : TEXCOORD2;
	float opacity : TEXCOORD3;
	float3 viewRight : TEXCOORD4;
	float3 viewUp : TEXCOORD5;
	float3 viewLook : TEXCOORD6;
};

VS_OUT VS(VS_IN vIn)
{
	VS_OUT vOut;

	float4 posW = float4(vIn.posL, 1.0f);//mul(float4(vIn.posL, 1.0f), gWorldMatrix);

	float3 viewLook = normalize(posW.xyz - gEyePosW);
	float3 viewRight = normalize(cross(float3(0,1,0), viewLook));
	float3 viewUp = cross(viewLook, viewRight);

	float2 vertexOffset = vIn.texCoord * float2(1, -1) + float2(-0.5, 0.5);
	posW.xyz += vIn.size * vertexOffset.x * viewRight;
	posW.xyz += vIn.size * vertexOffset.y * viewUp;

	vOut.posH = mul(posW, gViewProjMatrix);
	vOut.posW = posW.xyz;

	const float3 VOLUME_SIZE = float3(64, 16, 16);
	vOut.texCoord = vIn.texCoord;
	vOut.lightVolumeTexCoord = ((posW.xyz - gLightVolPos) / gLightVolScale) / VOLUME_SIZE;
	vOut.lightVolumeTexCoord.x += gLightTexOffsetX;
	vOut.opacity = vIn.opacity;

	vOut.viewRight = viewRight;
	vOut.viewUp = viewUp;
	vOut.viewLook = viewLook;

	return vOut;
}

#ifdef AXES_4
float3 calcLighting(float3 texCoord, float3 normal)
{
	const float3 axis0 = float3(0, 1, 0);
	const float3 axis1 = float3(0, -0.341987, 0.939705);
	const float3 axis2 = float3( 0.813808, -0.341987, -0.469852);
	const float3 axis3 = float3(-0.813808, -0.341987, -0.469852);

	float4 sample0 = gLightTex0.Sample(Trilinear, texCoord);
	float4 sample1 = gLightTex1.Sample(Trilinear, texCoord);
	float4 sample2 = gLightTex2.Sample(Trilinear, texCoord);

	float3 lightAcc = float3(0, 0, 0);
	lightAcc += saturate(dot(axis0, normal) * sample0.xyz);
	lightAcc += saturate(dot(axis1, normal) * sample1.xyz);
	lightAcc += saturate(dot(axis2, normal) * sample2.xyz);
	lightAcc += saturate(dot(axis3, normal) * float3(sample0.w, sample1.w, sample2.w));

	return lightAcc;
}
#else
float3 calcLighting(float3 texCoord, float3 normal)
{
	float4 sample0 = gLightTex0.Sample(Trilinear, texCoord);
	float4 sample1 = gLightTex1.Sample(Trilinear, texCoord);
	float4 sample2 = gLightTex2.Sample(Trilinear, texCoord);
	float4 sample3 = gLightTex3.Sample(Trilinear, texCoord);
	float4 sample4 = gLightTex4.Sample(Trilinear, texCoord);

	float3 lightAcc = float3(0, 0, 0);
	lightAcc += saturate( normal.x * sample0.xyz);
	lightAcc += saturate(-normal.x * sample1.xyz);
	lightAcc += saturate( normal.y * sample2.xyz);
	lightAcc += saturate(-normal.y * sample3.xyz);
	lightAcc += saturate( normal.z * sample4.xyz);
	lightAcc += saturate(-normal.z * float3(sample0.w, sample1.w, sample2.w));

	return lightAcc;
}
#endif


float4 PS(VS_OUT pIn) : SV_Target
{
	const float VOLUME_SIZE = 16;

	//float3 lightVolSpacePos = (pIn.posW - gLightVolPos) / gLightVolScale;

	//if( lightVolSpacePos.x > VOLUME_SIZE-1 || lightVolSpacePos.x < 0 ||
		//lightVolSpacePos.y > VOLUME_SIZE-1 || lightVolSpacePos.y < 0 ||
		//lightVolSpacePos.z > VOLUME_SIZE-1 || lightVolSpacePos.z < 0)
	//{
		//return float4(1.0f, 0.0f, 1.0f, 1.0f);
	//}

	//lightVolSpacePos /= VOLUME_SIZE;
	float3 lightVolSpacePos = pIn.lightVolumeTexCoord;

	float4 diffuseAndAlpha = gDiffuseMap.Sample(gTriLinearSam, pIn.texCoord);
	float3 normal = normalize(diffuseAndAlpha.xyz * 2 - 1);
	normal.x *= -1;
	float3x3 viewPosInv = float3x3(normalize(pIn.viewRight), normalize(pIn.viewUp), normalize(-pIn.viewLook));
	normal = normalize(mul(normal, viewPosInv));

	float3 lightAcc = float3(0, 0, 0);
	//lightAcc += saturate(dot(normal, gAxis0) * gLightTex0.Sample(Trilinear, lightVolSpacePos).rgb);
	//lightAcc += saturate(dot(normal, gAxis1) * gLightTex1.Sample(Trilinear, lightVolSpacePos).rgb);
	//lightAcc += saturate(dot(normal, gAxis2) * gLightTex2.Sample(Trilinear, lightVolSpacePos).rgb);
	//lightAcc += saturate(dot(normal, gAxis3) * gLightTex3.Sample(Trilinear, lightVolSpacePos).rgb);

	//float4 sample0 = gLightTex0.Sample(Trilinear, lightVolSpacePos);
	//float4 sample1 = gLightTex1.Sample(Trilinear, lightVolSpacePos);
	//float4 sample2 = gLightTex2.Sample(Trilinear, lightVolSpacePos);
	//float4 sample3 = gLightTex3.Sample(Trilinear, lightVolSpacePos);
	//float4 sample4 = gLightTex4.Sample(Trilinear, lightVolSpacePos);
//
	//lightAcc += saturate( normal.x * sample0.xyz);
	//lightAcc += saturate(-normal.x * sample1.xyz);
	//lightAcc += saturate( normal.y * sample2.xyz);
	//lightAcc += saturate(-normal.y * sample3.xyz);
	//lightAcc += saturate( normal.z * sample4.xyz);
	//lightAcc += saturate(-normal.z * float3(sample0.w, sample1.w, sample2.w));


	//lightAcc += saturate(-normal.y * gLightTex4.Sample(Trilinear, lightVolSpacePos).rgb);
	//lightAcc += saturate(-normal.z * gLightTex5.Sample(Trilinear, lightVolSpacePos).rgb);

	return float4(calcLighting(lightVolSpacePos, normal), diffuseAndAlpha.a * pIn.opacity);
}

technique11 tech
{
	pass P0
	{
		SetVertexShader( CompileShader( vs_5_0, VS() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_5_0, PS() ) );

		SetDepthStencilState(DepthWriteOff, 0);
		SetBlendState( Composite, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
	}
}
